<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // js运行三部曲： 1：语法分析（通篇检查是否出现语法错误） 2:预编译执行 3：（解释执行）解释型语言，解释一行，执行一行，自上而下
        // 预编译前奏： 1：函数声明整体提升  2： 变量的声明提升

        // 其中暗示全局变量： 任何变量如果未经声明就赋值，此变量归全局对象所有
        // console.log(window.a);  // undefined
        // console.log(window.b);  // undefined
        // function test1() {
        //     var a = b = 1;
        // }
        // test1();
        // console.log(b);         // 1
        // console.log(window.a);  // undefined
        // console.log(window.b);  // 1

        // console.log(a);
        // function a(num) {
        //     console.log(a);
        //     var a = 123;
        //     console.log(a)
        //     var a = function() {};
        //     console.log(a)
        // }
        // a(234);
        // var a = 345;
        // console.log(a)

        // ƒ a(num) {
        //     console.log(a);
        //     var a = 123;
        //     var a = function() {};
        //     console.log(a)
        // }
        // undefined
        // 123
        // ƒ () {}
        // 345

        // console.log(a);                                                 
        // function a(num) {
        //     console.log(a);
        //     a = 123;
        //     console.log(a)
        //     function a(){};
        //     console.log(a)
        // }
        // a(234);
        // var a = 345;
        // console.log(a)

        // ƒ a(num) {
        //     console.log(a);
        //     a = 123;
        //     function a() {};
        //     console.log(a)
        // }
        // ƒ a() {}
        // 123
        // 123
        // 345

        // 通过上面例子，，下面我们开始学习预编译
        // 预编译发生再函数执行的前一刻
        // GO：global object 全局对象，全局上下文
        // AO: activation object 活跃对象，函数上下文

        // GO：四部曲 1：创建GO对象 2：找变量声明，将变量作为GO对象的属性名，值为undefined 
        // 3：在函数体内找到函数声明，值赋予函数体 4：执行
        // AO：五部曲 1：创建GO对象 2：找形参与变量声明，将变量作为GO对象的属性名，值为undefined 
        // 3：将形参与实参值统一  4： 在函数体内找到函数声明，值赋予函数体  5：执行

        console.log(test2);
        function test2() {
            console.log(test2);
            test2 = 200;
            console.log(test2);
            var test2 = 300;
        }
        test2();
        console.log(test2);
        test2 = 100;
        var test2;
        console.log(test2);

        // GO 开始
        // 一： GO: {}
        // 二： GO：{ test2: undefined }
        // 三： GO: { test2: function test2(){...} }
        // 四： GO 开始解释执行
        // 执行一：console.log(test2) 打印为 fun; 执行二：test2()
        // AO 开始
        // 一： AO: {}
        // 二： AO: { test2: undefined }
        // 三： AO：无形参实参 { test2: undefined }
        // 四:  AO: 无函数声明 { test2: undefined }
        // 五:  AO开始戒指执行 
        // 执行一： console.log(test2) 打印undefined; 执行二: 赋值 { test2: 200 } 执行三：打印200； 执行四：赋值 { test2: 300 }
        // AO 结束
        // GO 执行三： console.log(test2) 打印 fun
        // GO 执行四： 赋值 { test2: 100 }
        // GO 执行五： console.log(test2) 打印 100
        // GO 结束

        // 实验发现：
        // 若AO中存在XX对象就在AO中拿，若无则去AO中获取。
        // 打印变量值 前面有赋值 则该值为赋值的值
        // 打印变量值之前没有赋值 有函数声明则值为函数声明 没有再看形参 再没有再看变量声明

    </script>
</body>
</html>